package com.ruyuan.user.server.controller.converter;

import com.ruyuan.common.model.Features;
import com.ruyuan.gateway.sdk.facade.RuyuanGatewayFacade;
import com.ruyuan.user.api.model.constants.UserAccountInfoExtendKeys;
import com.ruyuan.user.api.model.enums.AuthResourceTypeEnum;
import com.ruyuan.user.server.controller.request.SaveFunctionResourceRequest;
import com.ruyuan.user.server.controller.response.DataResourceAuthorityCategoryVO;
import com.ruyuan.user.server.controller.response.DataResourceAuthorityVO;
import com.ruyuan.user.server.controller.response.DataResourceVO;
import com.ruyuan.user.server.controller.response.FunctionResourceTreeVO;
import com.ruyuan.user.server.domain.model.AuthResource;
import com.ruyuan.user.server.domain.model.AuthResourceFeaturesKey;
import com.ruyuan.user.server.domain.model.Authority;
import com.ruyuan.user.server.domain.model.AuthorityFeaturesKey;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author xx
 */
@Component
public class WebAuthorityConverter {

    @Autowired
    private RuyuanGatewayFacade ruyuanGatewayFacade;

    public AuthResource convertSaveFunctionResourceRequestToModel(SaveFunctionResourceRequest request) {
        AuthResource authResource = new AuthResource();
        authResource.setId(request.getResourceId());
        authResource.setName(request.getName());
        authResource.setType(AuthResourceTypeEnum.getByCode(request.getResourceType()));
        authResource.setCode(request.getCode());
        authResource.setDescription(request.getDescription());
        authResource.setDeleted(false);
        authResource.setModifier(String.valueOf(ruyuanGatewayFacade.getCurrentUser().getUserId()));
        authResource.setOrgId(Long.valueOf(ruyuanGatewayFacade.getCurrentUser().getExtendInfo().get(UserAccountInfoExtendKeys.ROOT_ORG_ID)));
        if (StringUtils.isNotBlank(request.getUrl())) {
            authResource.getFeatures().addFeature(AuthResourceFeaturesKey.URL, request.getUrl());
        }
        if (StringUtils.isNotBlank(request.getIcon())) {
            authResource.getFeatures().addFeature(AuthResourceFeaturesKey.ICON, request.getIcon());
        }
        if (StringUtils.isNotBlank(request.getParentCode())) {
            authResource.getFeatures().addFeature(AuthResourceFeaturesKey.PARENT_CODE, request.getParentCode());
        }
        if (request.getEnable() != null) {
            authResource.getFeatures().addFeature(AuthResourceFeaturesKey.ENABLE, request.getEnable().toString());
        }
        if (request.getPriority() != null) {
            authResource.getFeatures().addFeature(AuthResourceFeaturesKey.PRIORITY, request.getPriority().toString());
        }
        return authResource;
    }

    public List<FunctionResourceTreeVO> convertModelToTreeVO(List<AuthResource> authResourceList) {
        // 先按parent分组
        Map<String, List<AuthResource>> parentCodeMap = groupByParentCode(authResourceList);
        // 再按code分组
        Map<String, AuthResource> functionResourceCodeMap = new HashMap<>();
        authResourceList.forEach(authResource -> functionResourceCodeMap.put(authResource.getCode(), authResource));
        // parentCode为空或者找不到的都放在第一级
        List<AuthResource> rootLevelFunction = new ArrayList<>();
        parentCodeMap.keySet().forEach(parentCode -> {
            if (!functionResourceCodeMap.containsKey(parentCode)) {
                rootLevelFunction.addAll(parentCodeMap.get(parentCode));
            }
        });
        // 递归构建树结构
        return buildAuthResourceTreeVO(rootLevelFunction, parentCodeMap);
    }

    public List<FunctionResourceTreeVO> buildAuthResourceTreeVO(List<AuthResource> currentLevelList, Map<String, List<AuthResource>> parentCodeMap) {
        if (CollectionUtils.isEmpty(currentLevelList)) {
            return null;
        }
        return currentLevelList.stream().map(authResource -> {
            FunctionResourceTreeVO functionResourceTreeVO = new FunctionResourceTreeVO();
            BeanUtils.copyProperties(authResource, functionResourceTreeVO);
            functionResourceTreeVO.setResourceId(authResource.getId());
            functionResourceTreeVO.setResourceType(authResource.getType().getCode());
            Features features = Optional.ofNullable(authResource.getFeatures()).orElse(Features.of());
            // 把features里的字段设置一下
            functionResourceTreeVO.setIcon(features.getFeature(AuthResourceFeaturesKey.ICON));
            functionResourceTreeVO.setParentCode(features.getFeature(AuthResourceFeaturesKey.PARENT_CODE));
            // 顺序没设置就放最后
            functionResourceTreeVO.setPriority(Optional.ofNullable(features.getFeature(AuthResourceFeaturesKey.PRIORITY)).map(Integer::parseInt).orElse(Integer.MAX_VALUE));
            functionResourceTreeVO.setEnable(Optional.ofNullable(features.getFeature(AuthResourceFeaturesKey.ENABLE)).map(Boolean::parseBoolean).orElse(true));
            functionResourceTreeVO.setUrl(Optional.ofNullable(features.getFeature(AuthResourceFeaturesKey.URL)).orElse(""));
            functionResourceTreeVO.setChildren(buildAuthResourceTreeVO(parentCodeMap.get(authResource.getCode()), parentCodeMap));
            return functionResourceTreeVO;
        }).sorted(Comparator.comparingInt(FunctionResourceTreeVO::getPriority)).collect(Collectors.toList());
    }

    public Map<String, List<AuthResource>> groupByParentCode(List<AuthResource> authResourceList) {
        Map<String, List<AuthResource>> parentCodeMap = new HashMap<>();
        authResourceList.forEach(authResource -> {
            String parentCode = Optional.ofNullable(Optional.ofNullable(authResource.getFeatures()).orElse(Features.of())
                    .getFeature(AuthResourceFeaturesKey.PARENT_CODE)).orElse("");
            parentCodeMap.computeIfAbsent(parentCode, key -> new ArrayList<>()).add(authResource);
        });
        return parentCodeMap;
    }

    public List<DataResourceVO> convertModelToDataResourceVO(List<AuthResource> authResourceList) {
        List<DataResourceVO> res = new ArrayList<>();
        if (CollectionUtils.isEmpty(authResourceList)) {
            return res;
        }
        for (AuthResource authResource : authResourceList) {
            DataResourceVO dataResourceVO = new DataResourceVO();
            dataResourceVO.setResourceId(authResource.getId());
            dataResourceVO.setName(authResource.getName());
            Map<String, List<Authority>> authorityGroupByCategory = authResource.getRelatedAuthorities().stream().collect(
                    Collectors.groupingBy(authority -> Optional.ofNullable(authority.getFeatures().getFeature(AuthorityFeaturesKey.CATEGORY)).orElse(""), Collectors.toList())
            );
            for (Map.Entry<String, List<Authority>> entry : authorityGroupByCategory.entrySet()) {
                DataResourceAuthorityCategoryVO dataResourceAuthorityCategoryVO = new DataResourceAuthorityCategoryVO();
                dataResourceAuthorityCategoryVO.setName(entry.getKey());
                dataResourceAuthorityCategoryVO.setAuthorityList(entry.getValue().stream().map(
                        authority -> {
                            DataResourceAuthorityVO dataResourceAuthorityVO = new DataResourceAuthorityVO();
                            dataResourceAuthorityVO.setAuthorityId(authority.getId());
                            dataResourceAuthorityVO.setName(authority.getName());
                            return dataResourceAuthorityVO;
                        }
                ).collect(Collectors.toList()));
                dataResourceVO.getAuthorityCategoryList().add(dataResourceAuthorityCategoryVO);
            }
            res.add(dataResourceVO);
        }
        return res;
    }

    public List<DataResourceVO> convertModelToRoleDataResourceVO(List<AuthResource> authResourceList, List<Long> roleAuthorities) {
        return authResourceList.stream().map(authResource -> {
            DataResourceVO dataResourceVO = new DataResourceVO();
            dataResourceVO.setResourceId(authResource.getId());
            dataResourceVO.setName(authResource.getName());
            Map<String, List<Authority>> authorityGroupByCategory = authResource.getRelatedAuthorities().stream()
                    .collect(Collectors.groupingBy(authority -> Optional.ofNullable(authority.getFeatures().getFeature(AuthorityFeaturesKey.CATEGORY)).orElse(""), Collectors.toList()));
            List<DataResourceAuthorityCategoryVO> authorityCategoryVOList = authorityGroupByCategory.keySet().stream().map(category -> {
                DataResourceAuthorityCategoryVO dataResourceAuthorityCategoryVO = new DataResourceAuthorityCategoryVO();
                dataResourceAuthorityCategoryVO.setName(category);
                dataResourceAuthorityCategoryVO.setAuthorityList(authorityGroupByCategory.get(category).stream().map(authority -> {
                    DataResourceAuthorityVO dataResourceAuthorityVO = new DataResourceAuthorityVO();
                    dataResourceAuthorityVO.setAuthorityId(authority.getId());
                    dataResourceAuthorityVO.setName(authority.getName());
                    dataResourceAuthorityVO.setChecked(roleAuthorities != null && roleAuthorities.contains(authority.getId()));
                    return dataResourceAuthorityVO;
                }).collect(Collectors.toList()));
                return dataResourceAuthorityCategoryVO;
            }).collect(Collectors.toList());
            dataResourceVO.setAuthorityCategoryList(authorityCategoryVOList);
            return dataResourceVO;
        }).collect(Collectors.toList());
    }

}
